Try..finally a inicializace promenne
Otázka od: Martin Burle
22. 10. 2002 16:34
Ahoj vsem,
nemam jasno v tom, kde vytvaret instanci objektu. Priklad:
try
Buf := TMemoryStream.Create;
....
finally
Buf.Free;
end;
takto mi to pripada spravne, lec kompilator ma za to, ze variable buf might
not have been initialized.
Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je snad
lepsi vytvorit objekt jeste pred try?
Diky,
Martin Burle, D6, W2k
Odpovedá: PeJaSoft
22. 10. 2002 18:05
Buf := TMemoryStream.Create;
try
....
finally
Buf.Free;
end;
Tohle se kompilatoru libit bude.
S pozdravem
Petr Jarkovsky
pejasoft@post.cz
----- Original Message -----
From: "Martin Burle" <mburle2@volny.cz>
> Ahoj vsem,
> nemam jasno v tom, kde vytvaret instanci objektu. Priklad:
>
> try
> Buf := TMemoryStream.Create;
> ....
> finally
> Buf.Free;
> end;
>
> takto mi to pripada spravne, lec kompilator ma za to, ze variable buf
might
> not have been initialized.
> Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je
snad
> lepsi vytvorit objekt jeste pred try?
> Diky,
> Martin Burle, D6, W2k
Odpovedá: Petr Vones
22. 10. 2002 17:39
From: "Martin Burle" <mburle2@volny.cz>
> nemam jasno v tom, kde vytvaret instanci objektu. Priklad:
>
> try
> Buf := TMemoryStream.Create;
> ....
> finally
> Buf.Free;
> end;
>
> takto mi to pripada spravne, lec kompilator ma za to, ze variable buf might
> not have been initialized.
> Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je snad
> lepsi vytvorit objekt jeste pred try?
Takhle je to nesmyslne, protoze ti jde o to mit garantovane uvolneni toho
objektu. Teoreticky totiz muze vzniknout vyjimka i v konstruktoru. Spravne:
Buf := TMemoryStream.Create;
try
....
finally
Buf.Free;
end;
Petr Vones
Odpovedá: Martin Cajbik
22. 10. 2002 16:39
Mozno je lepsie to napisat takto, vtedy by to nemalo hlasit nic
Buf:= nil;
try
Buf := TMemoryStream.Create;
....
finally
if Buf <> nil then
Buf.Free;
end;
MarCaNT (marcant@sct.sk)
> Ahoj vsem,
> nemam jasno v tom, kde vytvaret instanci objektu. Priklad:
>
> try
> Buf := TMemoryStream.Create;
> ....
> finally
> Buf.Free;
> end;
>
> takto mi to pripada spravne, lec kompilator ma za to, ze variable buf
might
> not have been initialized.
> Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je
snad
> lepsi vytvorit objekt jeste pred try?
> Diky,
> Martin Burle, D6, W2k
>
Odpovedá: Petr Vones
22. 10. 2002 17:31
From: "Martin Cajbik" <cajbik@sct.sk>
> Buf:= nil;
> try
Toto by melo smysl v pripade, ze chces snizit pocet vnorenych try..finally
bloku, napriklad:
var
InputStream, OutputStream: TMemoryStream;
begin
InputStream := TMemoryStream.Create;
try
OutputStream := TMemoryStream.Create;
try
finally
OutputStream.Free;
end;
finally
InputStream.Free;
end;
end;
upraveno jako:
var
InputStream, OutputStream: TMemoryStream;
begin
OutputStream := nil;
InputStream := TMemoryStream.Create;
try
OutputStream := TMemoryStream.Create;
finally
InputStream.Free;
OutputStream.Free;
end;
end;
> if Buf <> nil then
> Buf.Free;
Toto je nesmyslne, protoze metoda Free prave kontroluje zdali instance objektu
neni nil.
Petr Vones
Odpovedá: Martin Schayna
22. 10. 2002 17:23
----- Original Message -----
From: "Martin Burle" <mburle2@volny.cz>
> nemam jasno v tom, kde vytvaret instanci objektu. Priklad:
>
> try
> Buf := TMemoryStream.Create;
> ....
> finally
> Buf.Free;
> end;
>
> Jde se nejak teto hlasky trvale zbavit, pouze pro tento pripad? Nebo je snad
> lepsi vytvorit objekt jeste pred try?
Ano, pred try. Pokud behem volani constructoru dojde k vyjimce,
automaticky se zavola destructor takze neni treba osetrovat Create
pomoci try-finally.
V pripade podobnych nejasnosti je mozne kouknout na zdrojaky
napr. v (delphi)\Source\VCL, samozrejme krome rady RTFM
<g>.
Martin Schayna
Odpovedá: Martin Burle
22. 10. 2002 19:17
> Buf := TMemoryStream.Create;
> try
> ....
> finally
> Buf.Free;
> end;
Diky vsem, delal jsem to presne tak, tedy Create jeste pred try, ale nemel
jsem z toho uplne dobry pocit - ted uz jsem v klidu . Zmatlo me, ze create
v bloku try.. jsem videl v nekolika cizich zdrojacich, nepochybne
zkusenejsich autoru. Tedy proto, ze jsem RTFS <G> (nebyl to holt zdrojak
VCL).
Martin Burle
Odpovedá: Viliam Mlich
23. 10. 2002 6:00
>> if Buf <> nil then
>> Buf.Free;
> Toto je nesmyslne, protoze metoda Free prave
> kontroluje zdali instance objektu neni nil.
Na take nieco sa moze spoliehat len samovrah. Ale my jeptisky si aj na
sviecku natahujeme prezervativ.
bye
vmlich
Odpovedá: Jan Sebelík
23. 10. 2002 7:27
> Odesílatel: Viliam Mlich <vmlich@mbox.vol.cz>
> >> if Buf <> nil then
> >> Buf.Free;
> > Toto je nesmyslne, protoze metoda Free prave
> > kontroluje zdali instance objektu neni nil.
>
> Na take nieco sa moze spoliehat len samovrah. Ale my jeptisky si aj na
> sviecku natahujeme prezervativ.
Jasne, ale pak bychom mohli psat (pro jistotu)
if buf<>nil then
if buf<>nil then
buf.Free;
Honza
=========================================
= HAES - RNDr. Jan Sebelik
= http://www.haes.cz
= Skolici a konzultacni stredisko pro Delphi a Win32
= Vojtiskova 206
= 507 81 Lazne Belohrad
= tel. 493 792 931 (mobil 776 347735)
=========================================
Odpovedá: Dalibor Toman
23. 10. 2002 8:19
>> >> if Buf <> nil then
>> >> Buf.Free;
>> > Toto je nesmyslne, protoze metoda Free prave
>> > kontroluje zdali instance objektu neni nil.
>>
>> Na take nieco sa moze spoliehat len samovrah. Ale my jeptisky si aj
na
>> sviecku natahujeme prezervativ.
>Jasne, ale pak bychom mohli psat (pro jistotu)
>
>if buf<>nil then
> if buf<>nil then
> buf.Free;
to uz postrada smysl uplne.
Kontrola na Buf <> NIL je sice v pripade classes a metody Free
nadbytecna ale dovedu si predstavit, ze nekdo pak bude prilis spolehat
na to, ze NIL pointr odchyti nejaky jiny kod i v situaci, kdy to
nebude pravda (staci misto Class pouzit napriklad pointr na Object s
definovanou vlastni metodou Free).
Nebo staci ve vlastni classes prepsat si vhodne metodu Free
D. Toman
Odpovedá: eNca
23. 10. 2002 8:26
Viliam Mlich wrote:
>>> if Buf <> nil then
>>> Buf.Free;
>>>
>>>
>>Toto je nesmyslne, protoze metoda Free prave
>>kontroluje zdali instance objektu neni nil.
>>
>>
>
>Na take nieco sa moze spoliehat len samovrah. Ale my jeptisky si aj na
>sviecku natahujeme prezervativ.
>
>
procedure TObject.Free;
asm
TEST EAX,EAX // jestlize je instance nil,
JE @@exit // skoc na konec procedury
MOV ECX,[EAX] // jinak volej destruktor
MOV DL,1
CALL dword ptr [ECX].vmtDestroy
@@exit:
end;
Na toto se klidne spolehnu a sebevrah nejsem. Pokud toto povazujes za
nedostatecne, tak doporucuju neprogramovat, protoze by ses nemel
spolehat ani na to, ze
i:=0; skutecne vynuluje promennou i
eNca
Odpovedá: Viliam Mlich
23. 10. 2002 10:30
>>>> if Buf <> nil then
>>>> Buf.Free;
> procedure TObject.Free;
> Na toto se klidne spolehnu a sebevrah nejsem.
Ty sa na to kludne spoliehaj.
Hacik je v tom, ze tieto 2 riadky su v uplne inych suboroch a izolovany
zapis Buf.Free nehovori nic o tom, z coho je ten Buf, odvodeny. (Na to
vacsinou staci ocami skocit o par riadkov hore, to by este uslo.)
Ty si mozno pamatas, ze ked si to pisal, tak si metodu Free nemenil, ale
ten chudak, co by taky program po tebe musel udrziavat, by pri kazdom
probleme s uvolnovanim pamati musel kontrolovat, ci ta Free _nahodou_
nebola zmenena.
> tak doporucuju neprogramovat, protoze by ses nemel
:-) flejmovacie taktiky osvedcene z fida zaberaju aj na windozakov
Este budes musiet precitat hodne sprav, kym sa naucis vynechavat osobne
utoky..
bye
vmlich
Odpovedá: Ondrej Kelle
23. 10. 2002 10:40
> Ty si mozno pamatas, ze ked si to pisal, tak si metodu Free
> nemenil, ale ten chudak, co by taky program po tebe musel
> udrziavat, by pri kazdom probleme s uvolnovanim pamati
> musel kontrolovat, ci ta Free _nahodou_ nebola zmenena.
Tiez sa mi to zda prehnane. Metoda Free je staticka, takze menit sa da
jedine prepisanim v potomkovi (a tym padom schovanim povodnej metody v
predkovi).
Za prve mi to pripada ako neskutocna prasacina, za druhe nenapada ma jediny
dovod, preco by mohlo byt vhodne/potrebne prepisovat metodu Free, ked je tam
k dispozicii virtualny destructor Destroy.
Ale v podstate mas pravdu, ze taka moznost existuje.
BTW. Staticke metody su na rozdiel od dynamickych resolvovane pocas
kompilacie, takze dva nasledovne kusky kodu, aj ked zdanlivo podobne, budu
sa chovat uplne rozdielne:
type
TLeakingObject = class(TObject)
public
procedure Free;
end;
procedure TLeakingObject.Free;
begin
OutputDebugString('Just because you''re paranoid it doesn''t mean they''re
not after you.');
end;
procedure Proc1;
var
Obj: TLeakingObject;
begin
Obj := TLeakingObject.Create;
try
...
finally
Obj.Free; // memory leak v TLeakingObject.Free
end;
end;
procedure Proc2;
var
Obj: TObject;
begin
Obj := TLeakingObject.Create;
try
...
finally
Obj.Free; // uvolnenie pameti cez TObject.Free
end;
end;
Pri prepisovani statickych metod vo vseobecnosti plati, ze si treba na ne
davat velky pozor, hrozi totiz, ze pripadna chyba bude tazko odhalitelna.
Ak si spravne spominam, podla Dannyho Thorpa v knihe "Delphi Component
Design"
tuto moznost Delphi poskytuje iba kvoli prechodnym stavom, ked sa
menia velke hierarchie tried a potrebujes mat kod rychlo "up and running".
TOndrej
Odpovedá: Petr Vones
23. 10. 2002 14:46
From: "Viliam Mlich" <vmlich@mbox.vol.cz>
> Ty si mozno pamatas, ze ked si to pisal, tak si metodu Free nemenil, ale
> ten chudak, co by taky program po tebe musel udrziavat, by pri kazdom
> probleme s uvolnovanim pamati musel kontrolovat, ci ta Free _nahodou_
> nebola zmenena.
Stejne tak kontrolovat, jestli treba nebyl zmeneny konstruktor a nepridal se
tam kod na zformatovani disku Tohle je zkratka dobra demagogie. Pokud se
nekdo nekde snazil zmenit metodu Free tak je to samozrejme naprosto nesmyslna
vec, ktera by mela byt hned odhalena. Nejakym dalsim zbytecnym testovani nil
si moc nepomuzes, protoze tam mohl do Free pripsat treba
'if Day = 13 then
PInteger(nil)^ := 0' nebo nezavolal puvodni metodu Free a
mas hned dalsi
chybu.
Petr Vones
Odpovedá: Ludek ZITA
24. 10. 2002 20:48
Zdravim
Sledoval jsem s napetim tohle tema, ale nejsem z toho zrovna moudry
No a zrovna potrebuji v threadu dynamicky vytvaret podle situace konexi k
databazi.
No a kdyz uz jednou objekt Database a Query vytvorim a prikonektim k DB, pak
ho chci pouzit vicekrat a nerusit ho pro kazdy dotaz.
Takze klasicky postup create..try...akce...finally...free neprichazi v
uvahu.
Udelal jsem si zjednoduseny pokus :
procedure TForm1.Button1Click(Sender: TObject);
var TS: TStringList;
b: byte;
begin
if CheckBox1.Checked then
begin
TS := TStringList.Create;
TS.Text := 'BBB';
ShowMessage(TS.Text);
end
else
begin
ShowMessage('AAA');
end;
TS.Free;
end;
Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
nezaskrtnutem to ZRUSI BUTTON !!!
Jedine co pomuze je iniciovat promennou TS na NIL.
begin
TS := nil;
........
Pak to fuguje korektne. Ma to sice logiku, promenne by se mely
inicializovat, ale nema to nejake uskali ohledne korektniho uvolnovani
pameti a pod. ?
Je spravne toto :
procedure TExecThread.Execute;
var
ODBCDatabase: TODBCDatabase;
ODBCQuery: TODBCQuery;
procedure InitDB;
begin
if (ODBCDatabase <> nil) and (ODBCQuery <> nil) then
begin
// kontrola konexe
if not ODBCDatabase.Connected then ODBCDatabase.Open;
end else
begin
// pro jistotu kdyby byl uvolněn jen jeden objekt
if ODBCDatabase <> nil then ODBCDatabase.Free;
if ODBCQuery <> nil then ODBCQuery.Free;
// vytvořit
ODBCDatabase := TODBCDatabase.Create(Application);
ODBCQuery := TODBCQuery.Create(Application);
with ODBCQuery do
begin
Database := ODBCDatabase;
CursorType := ctDynamic;
end;
ODBCDatabase.ConnStr.text := SysUtils.StringReplace(FConnStr, ';',
';'#13#10, [rfReplaceAll]);
ODBCDatabase.Open;
end;
end;
begin
ODBCDatabase := nil;
ODBCQuery := nil;
try
// prvni blok
case mainmeny of
1:
begin
// kod bez konexe
end;
2: begin
// kod s konexi
InitDB;
ODBCQuery.SQL.text := 'select .....';
ODBCQuery.Open;
// .......
end;
end;
// druhý blok
case krok of
1:
begin
// kod bez konexe
end;
2: begin
// kod s konexi
InitDB;
ODBCQuery.SQL.text := 'select .....';
ODBCQuery.Open;
// .......
end;
end;
// pro jistotu pozavirame
if ODBCQuery.Active then ODBCQuery.Close;
if ODBCDatabase.Connected then ODBCDatabase.Close;
finally
// zrusime
if ODBCDatabase <> nil then ODBCDatabase.Free;
if ODBCQuery <> nil then ODBCQuery.Free;
end;
end;
Ve skutecnosti je to mnohem kosatejsi a k databazi se bud vubec
nepristoupi, nebo se otevira v nekolika ruznych mistech.
Dik
Ludek
----- Original Message -----
From: "Petr Vones" <pvones@mbox.vol.cz>
> From: "Martin Cajbik" <cajbik@sct.sk>
> > Buf:= nil;
> > try
>
> Toto by melo smysl v pripade, ze chces snizit pocet vnorenych try..finally
> bloku, napriklad:
....
Odpovedá: Lebeda David
25. 10. 2002 5:59
> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> b: byte;
> begin
> if CheckBox1.Checked then
> begin
> TS := TStringList.Create;
> TS.Text := 'BBB';
> ShowMessage(TS.Text);
> end
> else
> begin
> ShowMessage('AAA');
> end;
> TS.Free;
> end;
>
> Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
> nezaskrtnutem to ZRUSI BUTTON !!!
Hm, pokud neni zaskrtnuty checkbox, tak se jen zobrazi message 'AAA' a nasledne
se zavola free na TS. Jakozto neinicializovana promenna obsahuje zrejme nahodny
obsah, a proto se da tezko predvidat, co ten posledni radek vyvede. Spis bych
cekal
Access violation.
Reseni ale nespociva podle me v inicializaci na nil, ale v uprave logiky veci
tak, aby
se lokalni promenna uvolnovala jinde - uvnitr ifu, kde se TS vytvari apod.
Takhle
okus o vytvoreni probehne jen nekdy, zatimco uvolneni vzdy, a to je potreba
odstranit.
Pokud jsem nepochopil, k cemu tento prikladek smeroval, tak se omlouvam.
David Lebeda
Odpovedá: Lubos Urban
25. 10. 2002 8:30
Je to zaujimave ja som to skusil takto:
procedure TForm1.Button1Click(Sender: TObject);
var TS: TStringList;
begin
TS.Free;
end;
a Cela Forma posla niekde ale netusim kde lebo to neukoncilo aplikaciu
no a ked som to krokoval tak som sa dostal priamo sem
procedure TObject.Free;
asm
TEST EAX,EAX
JE @@exit
MOV ECX,[EAX]
MOV DL,1
CALL dword ptr [ECX].vmtDestroy
@@exit:
end;
a nie do destruktoru TStringListu;
Ked mi toto niekto vysvetli ze co robi ten kusok asembleru a preco to
nepadlo na destruktore TStringListu s AccesViolation
destructor TStringList.Destroy;
begin
FOnChange := nil;
FOnChanging := nil;
inherited Destroy;
if FCount <> 0 then Finalize(FList^[0], FCount);
FCount := 0;
SetCapacity(0);
end;
kde sa pristupuje k premennym triedy (FCount, FOnChanging .. ) ktore pri
neinstancovanych triedach by sa maly odkazovat len niekde do nealokovanej
pamate, budem vam povdacny
----- Original Message -----
From: "Ludek ZITA" <konference@sales.cz>
To: <delphi-l@clexpert.cz>
Sent: Thursday, October 24, 2002 9:20 PM
Subject: Re: Try..finally a inicializace promenne
> Zdravim
> Sledoval jsem s napetim tohle tema, ale nejsem z toho zrovna moudry
> No a zrovna potrebuji v threadu dynamicky vytvaret podle situace konexi k
> databazi.
> No a kdyz uz jednou objekt Database a Query vytvorim a prikonektim k DB,
pak
> ho chci pouzit vicekrat a nerusit ho pro kazdy dotaz.
> Takze klasicky postup create..try...akce...finally...free neprichazi v
> uvahu.
> Udelal jsem si zjednoduseny pokus :
>
> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> b: byte;
> begin
> if CheckBox1.Checked then
> begin
> TS := TStringList.Create;
> TS.Text := 'BBB';
> ShowMessage(TS.Text);
> end
> else
> begin
> ShowMessage('AAA');
> end;
> TS.Free;
> end;
>
> Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
> nezaskrtnutem to ZRUSI BUTTON !!!
>
> Jedine co pomuze je iniciovat promennou TS na NIL.
>
> begin
> TS := nil;
> ........
>
> Pak to fuguje korektne. Ma to sice logiku, promenne by se mely
> inicializovat, ale nema to nejake uskali ohledne korektniho uvolnovani
> pameti a pod. ?
>
> Je spravne toto :
>
> procedure TExecThread.Execute;
> var
> ODBCDatabase: TODBCDatabase;
> ODBCQuery: TODBCQuery;
>
> procedure InitDB;
> begin
> if (ODBCDatabase <> nil) and (ODBCQuery <> nil) then
> begin
> // kontrola konexe
> if not ODBCDatabase.Connected then ODBCDatabase.Open;
> end else
> begin
> // pro jistotu kdyby byl uvolněn jen jeden objekt
> if ODBCDatabase <> nil then ODBCDatabase.Free;
> if ODBCQuery <> nil then ODBCQuery.Free;
> // vytvořit
> ODBCDatabase := TODBCDatabase.Create(Application);
> ODBCQuery := TODBCQuery.Create(Application);
> with ODBCQuery do
> begin
> Database := ODBCDatabase;
> CursorType := ctDynamic;
> end;
> ODBCDatabase.ConnStr.text := SysUtils.StringReplace(FConnStr, ';',
> ';'#13#10, [rfReplaceAll]);
> ODBCDatabase.Open;
> end;
> end;
>
> begin
> ODBCDatabase := nil;
> ODBCQuery := nil;
> try
> // prvni blok
> case mainmeny of
> 1:
> begin
> // kod bez konexe
> end;
> 2: begin
> // kod s konexi
> InitDB;
> ODBCQuery.SQL.text := 'select .....';
> ODBCQuery.Open;
> // .......
> end;
> end;
>
> // druhý blok
> case krok of
> 1:
> begin
> // kod bez konexe
> end;
> 2: begin
> // kod s konexi
> InitDB;
> ODBCQuery.SQL.text := 'select .....';
> ODBCQuery.Open;
> // .......
> end;
> end;
> // pro jistotu pozavirame
> if ODBCQuery.Active then ODBCQuery.Close;
> if ODBCDatabase.Connected then ODBCDatabase.Close;
> finally
> // zrusime
> if ODBCDatabase <> nil then ODBCDatabase.Free;
> if ODBCQuery <> nil then ODBCQuery.Free;
> end;
> end;
>
>
>
> Ve skutecnosti je to mnohem kosatejsi a k databazi se bud vubec
> nepristoupi, nebo se otevira v nekolika ruznych mistech.
>
> Dik
> Ludek
>
>
> ----- Original Message -----
> From: "Petr Vones" <pvones@mbox.vol.cz>
> > From: "Martin Cajbik" <cajbik@sct.sk>
> > > Buf:= nil;
> > > try
> >
> > Toto by melo smysl v pripade, ze chces snizit pocet vnorenych
try..finally
> > bloku, napriklad:
> ....
>
>
>
Odpovedá: Petr Langer
25. 10. 2002 9:19
Tak presne na toto jsem se ptal nedavno (asi tri ctyri dny zpatky) tady v
konferenci . Pokud to pouzijes jako lokalni promenou, tak na zacatku, v
begin NENI objekt = nil, takze to na free vyhuci.
petr
----- Original Message -----
From: "Lubos Urban" <Lubos.Urban@visicom.sk>
To: <delphi-l@clexpert.cz>
Sent: Friday, October 25, 2002 9:05 AM
Subject: Re: Try..finally a inicializace promenne
> Je to zaujimave ja som to skusil takto:
>
> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> begin
> TS.Free;
> end;
>
> a Cela Forma posla niekde ale netusim kde lebo to neukoncilo aplikaciu
>
> no a ked som to krokoval tak som sa dostal priamo sem
>
> procedure TObject.Free;
> asm
> TEST EAX,EAX
> JE @@exit
> MOV ECX,[EAX]
> MOV DL,1
> CALL dword ptr [ECX].vmtDestroy
> @@exit:
> end;
>
> a nie do destruktoru TStringListu;
>
> Ked mi toto niekto vysvetli ze co robi ten kusok asembleru a preco to
> nepadlo na destruktore TStringListu s AccesViolation
>
> destructor TStringList.Destroy;
> begin
> FOnChange := nil;
> FOnChanging := nil;
> inherited Destroy;
> if FCount <> 0 then Finalize(FList^[0], FCount);
> FCount := 0;
> SetCapacity(0);
> end;
>
> kde sa pristupuje k premennym triedy (FCount, FOnChanging .. ) ktore pri
> neinstancovanych triedach by sa maly odkazovat len niekde do nealokovanej
> pamate, budem vam povdacny
>
> ----- Original Message -----
> From: "Ludek ZITA" <konference@sales.cz>
> To: <delphi-l@clexpert.cz>
> Sent: Thursday, October 24, 2002 9:20 PM
> Subject: Re: Try..finally a inicializace promenne
>
>
> > Zdravim
> > Sledoval jsem s napetim tohle tema, ale nejsem z toho zrovna moudry
> > No a zrovna potrebuji v threadu dynamicky vytvaret podle situace konexi
k
> > databazi.
> > No a kdyz uz jednou objekt Database a Query vytvorim a prikonektim k DB,
> pak
> > ho chci pouzit vicekrat a nerusit ho pro kazdy dotaz.
> > Takze klasicky postup create..try...akce...finally...free neprichazi v
> > uvahu.
> > Udelal jsem si zjednoduseny pokus :
> >
> > procedure TForm1.Button1Click(Sender: TObject);
> > var TS: TStringList;
> > b: byte;
> > begin
> > if CheckBox1.Checked then
> > begin
> > TS := TStringList.Create;
> > TS.Text := 'BBB';
> > ShowMessage(TS.Text);
> > end
> > else
> > begin
> > ShowMessage('AAA');
> > end;
> > TS.Free;
> > end;
> >
> > Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
> > nezaskrtnutem to ZRUSI BUTTON !!!
> >
> > Jedine co pomuze je iniciovat promennou TS na NIL.
> >
> > begin
> > TS := nil;
> > ........
> >
> > Pak to fuguje korektne. Ma to sice logiku, promenne by se mely
> > inicializovat, ale nema to nejake uskali ohledne korektniho uvolnovani
> > pameti a pod. ?
> >
> > Je spravne toto :
> >
> > procedure TExecThread.Execute;
> > var
> > ODBCDatabase: TODBCDatabase;
> > ODBCQuery: TODBCQuery;
> >
> > procedure InitDB;
> > begin
> > if (ODBCDatabase <> nil) and (ODBCQuery <> nil) then
> > begin
> > // kontrola konexe
> > if not ODBCDatabase.Connected then ODBCDatabase.Open;
> > end else
> > begin
> > // pro jistotu kdyby byl uvolněn jen jeden objekt
> > if ODBCDatabase <> nil then ODBCDatabase.Free;
> > if ODBCQuery <> nil then ODBCQuery.Free;
> > // vytvořit
> > ODBCDatabase := TODBCDatabase.Create(Application);
> > ODBCQuery := TODBCQuery.Create(Application);
> > with ODBCQuery do
> > begin
> > Database := ODBCDatabase;
> > CursorType := ctDynamic;
> > end;
> > ODBCDatabase.ConnStr.text := SysUtils.StringReplace(FConnStr, ';',
> > ';'#13#10, [rfReplaceAll]);
> > ODBCDatabase.Open;
> > end;
> > end;
> >
> > begin
> > ODBCDatabase := nil;
> > ODBCQuery := nil;
> > try
> > // prvni blok
> > case mainmeny of
> > 1:
> > begin
> > // kod bez konexe
> > end;
> > 2: begin
> > // kod s konexi
> > InitDB;
> > ODBCQuery.SQL.text := 'select .....';
> > ODBCQuery.Open;
> > // .......
> > end;
> > end;
> >
> > // druhý blok
> > case krok of
> > 1:
> > begin
> > // kod bez konexe
> > end;
> > 2: begin
> > // kod s konexi
> > InitDB;
> > ODBCQuery.SQL.text := 'select .....';
> > ODBCQuery.Open;
> > // .......
> > end;
> > end;
> > // pro jistotu pozavirame
> > if ODBCQuery.Active then ODBCQuery.Close;
> > if ODBCDatabase.Connected then ODBCDatabase.Close;
> > finally
> > // zrusime
> > if ODBCDatabase <> nil then ODBCDatabase.Free;
> > if ODBCQuery <> nil then ODBCQuery.Free;
> > end;
> > end;
> >
> >
> >
> > Ve skutecnosti je to mnohem kosatejsi a k databazi se bud vubec
> > nepristoupi, nebo se otevira v nekolika ruznych mistech.
> >
> > Dik
> > Ludek
> >
> >
> > ----- Original Message -----
> > From: "Petr Vones" <pvones@mbox.vol.cz>
> > > From: "Martin Cajbik" <cajbik@sct.sk>
> > > > Buf:= nil;
> > > > try
> > >
> > > Toto by melo smysl v pripade, ze chces snizit pocet vnorenych
> try..finally
> > > bloku, napriklad:
> > ....
> >
> >
> >
>
>
>
Odpovedá: Lubos Urban
25. 10. 2002 8:42
No tak uz som dostal vysvetlenie
Kedze pri instanciovani objektu sa vytvaraju iba jeho data a nie metody,
ktore su pre vsetky objekty tej istej classy spolocne, tak mozme zavolat
hociaku funckciu aj neinstancoivaneho objektu (Free) ktora ako prvy
parameter dostane self co je vlastne parameter na objekt ktory funkciu vola.
Kedze v Delphi nie su lokalne premenne automaticky nastavovane na defaultne
hodnoty na rozdiel od premennych deklarovanych v triede vyzera to asi
nesledovne ak sa nemylim:
procedure TForm1.Button1Click(Sender: TObject);
var TS: TStringList;
begin
// TS nieje nil;
TS.Free;
end
procedure TObject.Free;
asm
TEST EAX,EAX
JE @@exit
// porovnanie ci EAX prvy parameter funkcie (self) nie je 0 (nil)
// a kedze pri lokalnych premmeny ich hodnoty niesu nastavovane na nil
// tak tam nil nieje a funkcia nekonci a pokracuje
// a ked mame smolku tak v EAX je nejaka platna adresa napr na Formu
// alebo nejaku inu komponentu a zdestruujde sa ta
MOV ECX,[EAX]
MOV DL,1
CALL dword ptr [ECX].vmtDestroy
@@exit:
end;
==========================
ak by bola TS delklarovana v triede TForm1 vypadalo by to asi takto:
procedure TForm1.Button1Click(Sender: TObject);
begin
// TS je nil lebo premenne deklarovane v triede su automaticky
inicializovane na defaultne hodnoty
// v tomto pripade nil
TS.Free;
end
procedure TObject.Free;
asm
TEST EAX,EAX
JE @@exit
// porovnanie ci EAX prvy parameter funkcie (self) nie je 0 (nil)
// EAX je 0 (nil) funcia konci nic sa nedestrojuje
MOV ECX,[EAX]
MOV DL,1
CALL dword ptr [ECX].vmtDestroy
@@exit:
end;
=========================
Zaver: Vzdy inicializovat lokalne premenne, najma ak su to instancie tried
----- Original Message -----
From: "Lubos Urban" <Lubos.Urban@visicom.sk>
To: <delphi-l@clexpert.cz>
Sent: Friday, October 25, 2002 9:05 AM
Subject: Re: Try..finally a inicializace promenne
> Je to zaujimave ja som to skusil takto:
>
> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> begin
> TS.Free;
> end;
>
> a Cela Forma posla niekde ale netusim kde lebo to neukoncilo aplikaciu
>
> no a ked som to krokoval tak som sa dostal priamo sem
>
> procedure TObject.Free;
> asm
> TEST EAX,EAX
> JE @@exit
> MOV ECX,[EAX]
> MOV DL,1
> CALL dword ptr [ECX].vmtDestroy
> @@exit:
> end;
>
> a nie do destruktoru TStringListu;
>
> Ked mi toto niekto vysvetli ze co robi ten kusok asembleru a preco to
> nepadlo na destruktore TStringListu s AccesViolation
>
> destructor TStringList.Destroy;
> begin
> FOnChange := nil;
> FOnChanging := nil;
> inherited Destroy;
> if FCount <> 0 then Finalize(FList^[0], FCount);
> FCount := 0;
> SetCapacity(0);
> end;
>
> kde sa pristupuje k premennym triedy (FCount, FOnChanging .. ) ktore pri
> neinstancovanych triedach by sa maly odkazovat len niekde do nealokovanej
> pamate, budem vam povdacny
>
> ----- Original Message -----
> From: "Ludek ZITA" <konference@sales.cz>
> To: <delphi-l@clexpert.cz>
> Sent: Thursday, October 24, 2002 9:20 PM
> Subject: Re: Try..finally a inicializace promenne
>
>
> > Zdravim
> > Sledoval jsem s napetim tohle tema, ale nejsem z toho zrovna moudry
> > No a zrovna potrebuji v threadu dynamicky vytvaret podle situace konexi
k
> > databazi.
> > No a kdyz uz jednou objekt Database a Query vytvorim a prikonektim k DB,
> pak
> > ho chci pouzit vicekrat a nerusit ho pro kazdy dotaz.
> > Takze klasicky postup create..try...akce...finally...free neprichazi v
> > uvahu.
> > Udelal jsem si zjednoduseny pokus :
> >
> > procedure TForm1.Button1Click(Sender: TObject);
> > var TS: TStringList;
> > b: byte;
> > begin
> > if CheckBox1.Checked then
> > begin
> > TS := TStringList.Create;
> > TS.Text := 'BBB';
> > ShowMessage(TS.Text);
> > end
> > else
> > begin
> > ShowMessage('AAA');
> > end;
> > TS.Free;
> > end;
> >
> > Takze tohle samozrejme pri zaskrtnutem checkboxu funguje, ale pri
> > nezaskrtnutem to ZRUSI BUTTON !!!
> >
> > Jedine co pomuze je iniciovat promennou TS na NIL.
> >
> > begin
> > TS := nil;
> > ........
> >
> > Pak to fuguje korektne. Ma to sice logiku, promenne by se mely
> > inicializovat, ale nema to nejake uskali ohledne korektniho uvolnovani
> > pameti a pod. ?
> >
> > Je spravne toto :
> >
> > procedure TExecThread.Execute;
> > var
> > ODBCDatabase: TODBCDatabase;
> > ODBCQuery: TODBCQuery;
> >
> > procedure InitDB;
> > begin
> > if (ODBCDatabase <> nil) and (ODBCQuery <> nil) then
> > begin
> > // kontrola konexe
> > if not ODBCDatabase.Connected then ODBCDatabase.Open;
> > end else
> > begin
> > // pro jistotu kdyby byl uvolněn jen jeden objekt
> > if ODBCDatabase <> nil then ODBCDatabase.Free;
> > if ODBCQuery <> nil then ODBCQuery.Free;
> > // vytvořit
> > ODBCDatabase := TODBCDatabase.Create(Application);
> > ODBCQuery := TODBCQuery.Create(Application);
> > with ODBCQuery do
> > begin
> > Database := ODBCDatabase;
> > CursorType := ctDynamic;
> > end;
> > ODBCDatabase.ConnStr.text := SysUtils.StringReplace(FConnStr, ';',
> > ';'#13#10, [rfReplaceAll]);
> > ODBCDatabase.Open;
> > end;
> > end;
> >
> > begin
> > ODBCDatabase := nil;
> > ODBCQuery := nil;
> > try
> > // prvni blok
> > case mainmeny of
> > 1:
> > begin
> > // kod bez konexe
> > end;
> > 2: begin
> > // kod s konexi
> > InitDB;
> > ODBCQuery.SQL.text := 'select .....';
> > ODBCQuery.Open;
> > // .......
> > end;
> > end;
> >
> > // druhý blok
> > case krok of
> > 1:
> > begin
> > // kod bez konexe
> > end;
> > 2: begin
> > // kod s konexi
> > InitDB;
> > ODBCQuery.SQL.text := 'select .....';
> > ODBCQuery.Open;
> > // .......
> > end;
> > end;
> > // pro jistotu pozavirame
> > if ODBCQuery.Active then ODBCQuery.Close;
> > if ODBCDatabase.Connected then ODBCDatabase.Close;
> > finally
> > // zrusime
> > if ODBCDatabase <> nil then ODBCDatabase.Free;
> > if ODBCQuery <> nil then ODBCQuery.Free;
> > end;
> > end;
> >
> >
> >
> > Ve skutecnosti je to mnohem kosatejsi a k databazi se bud vubec
> > nepristoupi, nebo se otevira v nekolika ruznych mistech.
> >
> > Dik
> > Ludek
> >
> >
> > ----- Original Message -----
> > From: "Petr Vones" <pvones@mbox.vol.cz>
> > > From: "Martin Cajbik" <cajbik@sct.sk>
> > > > Buf:= nil;
> > > > try
> > >
> > > Toto by melo smysl v pripade, ze chces snizit pocet vnorenych
> try..finally
> > > bloku, napriklad:
> > ....
> >
> >
> >
>
>
>
Odpovedá: Lukas Gebauer
25. 10. 2002 8:51
> destructor TStringList.Destroy;
> begin
> FOnChange := nil;
> FOnChanging := nil;
> inherited Destroy;
> if FCount <> 0 then Finalize(FList^[0], FCount);
> FCount := 0;
> SetCapacity(0);
> end;
Tak ty nejdrive ten objekt peclive zlikvidujes (tim inherited
Destroy), a pak se snazis pristupovat k jeho promennym (FCount) a
jeste navic pristupovat k jeho metodam (setCapacity).. to preci musi
zbuchnout, ne?
-- Lukas Gebauer.
E-mail: gebauerl@mlp.cz
http://www.ararat.cz/synapse/ - Synapse Delphi and Kylix TCP/IP Lib.
Odpovedá: Lubos Urban
25. 10. 2002 9:07
To je original Borlandovsky zdrojak (classes.pas
----- Original Message -----
From: "Lukas Gebauer" <gebylist@mlp.cz>
To: <delphi-l@clexpert.cz>
Sent: Friday, October 25, 2002 9:41 AM
Subject: Re: Try..finally a inicializace promenne
> > destructor TStringList.Destroy;
> > begin
> > FOnChange := nil;
> > FOnChanging := nil;
> > inherited Destroy;
> > if FCount <> 0 then Finalize(FList^[0], FCount);
> > FCount := 0;
> > SetCapacity(0);
> > end;
>
> Tak ty nejdrive ten objekt peclive zlikvidujes (tim inherited
> Destroy), a pak se snazis pristupovat k jeho promennym (FCount) a
> jeste navic pristupovat k jeho metodam (setCapacity).. to preci musi
> zbuchnout, ne?
>
>
>
> -- Lukas Gebauer.
>
> E-mail: gebauerl@mlp.cz
> http://www.ararat.cz/synapse/ - Synapse Delphi and Kylix TCP/IP Lib.
>
>
>
Odpovedá: Ondrej Kelle
25. 10. 2002 9:37
> procedure TForm1.Button1Click(Sender: TObject);
> var TS: TStringList;
> begin
> TS.Free;
> end;
>
> a Cela Forma posla niekde ale netusim kde lebo to neukoncilo aplikaciu
>
> no a ked som to krokoval tak som sa dostal priamo sem
>
> procedure TObject.Free;
> asm
> TEST EAX,EAX
> JE @@exit
> MOV ECX,[EAX]
> MOV DL,1
> CALL dword ptr [ECX].vmtDestroy
> @@exit:
> end;
>
> a nie do destruktoru TStringListu;
>
> Ked mi toto niekto vysvetli ze co robi ten kusok asembleru a preco to
> nepadlo na destruktore TStringListu s AccesViolation
ten kusok asembleru robi toto:
procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;
Cize volas proceduru Free, ktora skontroluje, ci je dana premenna nil, a ak
nie je, zavola virtualny Destroy, tzn. vo VMT (virtual method table) danej
instancie sa vyhlada adresa Destroy posledneho potomka, ktory overridol
Destroy a ta sa zavola. Ked je ten pointer neinicializovany, potom aj jeho
VMT je sada divokych pointrov
VMT ma myslim negativne offsety od Self, takze je mozne, ze to na tych
adresach nahodou naslo odkaz na Destroy toho formulara. Tam si potom dostal
AV pretoze nie je mozne destruovat windowed control v kontexte spracovania
spravy (WM_LBUTTONUP) Ale to su uz dohady. Skratka, neinicializovany pointer
ukazuje na blok pameti s nedefinovanym obsahom, takze pri jeho pouziti sa
moze stat _cokolvek_.
Jedna stara cinska kliatba vraj znela "Nech je Tvoj zivot zaujimavy".
HTH
TOndrej
Odpovedá: Števlík Marián
25. 10. 2002 10:45
Ak sa mozem pripojit do diskusie, tak by som sa chcel tiez nieco spytat
ohladom try ... finally
Majme nieco taketo:
var
Obj1: TObj1;
Obj2: TObj2;
begin
Obj1 := TObj1.Create(...);
try
try
...
if (NejakaPodmienka) then
begin
Obj2 := TObj2.Create(...);
try
...
finally
Obj2.Free;
end;
end;
...
except
ShowMessage('Chyba!');
end;
finally
Obj1.Free;
end;
end;
No a otazka znie
Ak sa vyskytne nejaka chyba medzi try ... finally pre Obj2 tak sa odchyti az
vtom jedinom except, ale je otazne ci sa predtym este zavola to Obj2.Free v
jeho finally, alebo sa rovno skoci do except a Obj2 ostane vysiet v pamati?
Stevlik Marian
Software Development Specialist
MERLIN
Stefanikova 32
150 00 Prague 5
Czech Republic
e-mail: marian.stevlik@merlin.cz
tel: +420 241010111 (181)
fax: +420 241010165
ICQ: 38493645
Odpovedá: Petr Langer
25. 10. 2002 11:02
zavola se v kazdem pripade, ale jak jsi spravne uvedl, tak tam ta chyba
neskonci, ale predava s pak dal az to nejblizsiho except.
petr
----- Original Message -----
From: "Števlík Marián" <Marian.Stevlik@merlin.cz>
To: <delphi-l@clexpert.cz>
Sent: Friday, October 25, 2002 11:02 AM
Subject: RE: Try..finally a inicializace promenne
> Ak sa mozem pripojit do diskusie, tak by som sa chcel tiez nieco spytat
> ohladom try ... finally
> Majme nieco taketo:
>
> var
> Obj1: TObj1;
> Obj2: TObj2;
> begin
> Obj1 := TObj1.Create(...);
> try
> try
> ...
> if (NejakaPodmienka) then
> begin
> Obj2 := TObj2.Create(...);
> try
> ...
> finally
> Obj2.Free;
> end;
> end;
> ...
> except
> ShowMessage('Chyba!');
> end;
> finally
> Obj1.Free;
> end;
> end;
>
> No a otazka znie
> Ak sa vyskytne nejaka chyba medzi try ... finally pre Obj2 tak sa odchyti
az
> vtom jedinom except, ale je otazne ci sa predtym este zavola to Obj2.Free
v
> jeho finally, alebo sa rovno skoci do except a Obj2 ostane vysiet v
pamati?
>
> Stevlik Marian
> Software Development Specialist
> MERLIN
> Stefanikova 32
> 150 00 Prague 5
> Czech Republic
> e-mail: marian.stevlik@merlin.cz
> tel: +420 241010111 (181)
> fax: +420 241010165
> ICQ: 38493645
>
>
Odpovedá: Ondrej Kelle
25. 10. 2002 10:39
> var
> Obj1: TObj1;
> Obj2: TObj2;
> begin
> Obj1 := TObj1.Create(...);
> try
> try
> ...
> if (NejakaPodmienka) then
> begin
> Obj2 := TObj2.Create(...);
> try
> ...
> finally
> Obj2.Free;
> end;
> end;
> ...
> except
> ShowMessage('Chyba!');
> end;
> finally
> Obj1.Free;
> end;
> end;
>
> No a otazka znie
> Ak sa vyskytne nejaka chyba medzi try ... finally pre Obj2
> tak sa odchyti az vtom jedinom except, ale je otazne ci
> sa predtym este zavola to Obj2.Free v jeho finally, alebo
> sa rovno skoci do except a Obj2 ostane vysiet v pamati?
Ved si to mozes odkrokovat. Obj2.Free sa zavola este pred tym except blokom.
try..finally prave zaruci, ze finally blok sa vykona bez ohladu na to, ci v
bloku try nastala vynimka.
HTH
TOndrej
Odpovedá: Petr Fejfar
25. 10. 2002 11:45
From: "Ondrej Kelle" <O.Kelle@digitalpublishing.de>
> Skratka, neinicializovany pointer
> ukazuje na blok pameti s nedefinovanym obsahom,
Jen technicka poznamka: Proc s nedefinovanym?
Je-li ten pointer automatickou promennou, tak se alokuje na stacku posunutim
SP a tak
neinicializovany pointer muze stejne dobre
obsahovat napr. odkaz na platnou
(existujici) instanci nektere tridy, ktera se
predavala jako argument popr. self pri nekterem
z predchozich volani podprogramu s vetsi hloubkou vnoreni zasobniku.
Bye, pf
Odpovedá: Ondrej Kelle
25. 10. 2002 12:04
>> Skratka, neinicializovany pointer
>> ukazuje na blok pameti s nedefinovanym obsahom,
>
> Jen technicka poznamka: Proc s nedefinovanym?
>
> Je-li ten pointer automatickou promennou, tak se alokuje na
> stacku posunutim SP a tak neinicializovany pointer muze
> stejne dobre obsahovat napr. odkaz na platnou (existujici)
> instanci nektere tridy, ktera se predavala jako argument popr.
> self pri nekterem z predchozich volani podprogramu s vetsi
> hloubkou vnoreni zasobniku.
Hm, zle som sa vyjadril. Chcel som povedat, ze neinicializovana premenna
typu pointer ukazuje niekam na nahodnu adresu. Moze to byt niekam uplne do
blba, alebo nahodou aj na platnu instanciu, ako hovoris.
Velmi pravdepodobne vsak neukazuje tam, kde to autor ocakaval.
Je to takto spravne alebo som uplne mimo ako ten pointer?
Dik za opravu.
TOndrej
Odpovedá: Martin Schayna
25. 10. 2002 13:21
----- Original Message -----
From: "Petr Fejfar" <development@callnet.cz>
> Je-li ten pointer automatickou promennou, tak se
> alokuje na stacku posunutim SP a tak neinicializovany
> pointer muze stejne dobre obsahovat napr. odkaz na
> platnou (existujici) instanci nektere tridy, ktera se
> predavala jako argument popr. self pri nekterem
> z predchozich volani podprogramu s vetsi hloubkou
> vnoreni zasobniku.
Nehrajme si se slovicky, proste to znamena ze se
programator nemuze spolehnout co v takovem pointeru
je a rozhodne s tim nemuze pocitat.
Odpovedá: Petr Fejfar
25. 10. 2002 15:29
From: "Martin Schayna" <mschayna@aktis.cz>
> Nehrajme si se slovicky, proste to znamena
> ze se programator nemuze spolehnout co v takovem
> pointeru je a rozhodne s tim nemuze pocitat.
Kdyby tohle bylo kazdemu jasne
(tim nemam na mysli TOndreje), tak se nebudou
v konferenci stale dokola opakovat dotazy
tohoto typu, nehlede na to, ze ve vsech uvadenych
prikladech na neinicializovanou promennou
upozorni prekladac Warningem, tudiz v podstate
neni co resit ani o cem diskutovat.
Bye, pf